2014-04-15 3 views
5

Насколько я могу судить, gson не выполняет автоматическую сериализацию и десериализацию объектов java.util.Date в строках ISO, таких как «yyyy-MM-ddTHH: mm: ssZ» или, например, 2014-04-15T18: 22: 00-05: 00" . Поэтому для того, чтобы я мог правильно сообщать даты между моим клиентом (с использованием Retrofit with gson) и сервером, мне нужно указать DateFormat для gson. Вот что я сделал:Пользовательский десериализатор gson для даты никогда не называется

// code defining the creation of a RestAdapter 
// ... 
new GsonBuilder() 
    .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") 
    .create() 

Добавление .setDateFormat линии было достаточно, чтобы получить gson правильно десериализации временных меток строк в Дата объектов. Однако он не сериализовал объекты Date в строках timestamp. Поэтому я предположил, что я должен был бы создать пользовательский сериализатор так:

// code defining the creation of a RestAdapter 
// ... 
new GsonBuilder() 
    .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") 
    .registerTypeAdapter(Date.class, new DateSerializer()) 
    .create() 

и класс DateSerializer:

class DateSerializer implements JsonSerializer<Date> { 
    @Override 
    public JsonElement serialize(Date arg0, Type arg1, JsonSerializationContext arg2) { 
     SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US); 
     return new JsonPrimitive(df.format(arg0)); 
    } 
} 

К сожалению, функция сериализации игнорируется. Вместо этого gson форматирует дату как строку типа «Вт Мар 15 18:22:00 EST 2014». Таким образом, чтобы проверить, я попытался заменить функцию сериализации с:

public JsonElement serialize(Date arg0, Type arg1, JsonSerializationContext arg2) { 
    throw new RuntimeException("Serialize function called!"); 
} 

Но, конечно же, что RuntimeException никогда не выброшен.

Кто-нибудь знает, почему моя функция сериализации игнорируется? Я думаю, что я где-то читал, что для некоторых типов registerTypeAdapter будет проигнорирован, если для суперкласса определен один, но поскольку это java.util.Date, я бы смутился, если бы это была проблема. Я, наверное, просто делаю что-то глупое, но я, вероятно, не знаю Даты или Гэна достаточно хорошо, чтобы понять это.

EDIT: При условии, больше контекста вокруг кода ниже:

MyApplication.java

public class MyApplication extends Application { 
    public static RestAdapter restAdapter; 
    public static The1Api the1Api; 

    public static void createRestAdapter(String server_url){ 
     // enable cookies 
     CookieManager cookieManager = new CookieManager(); 
     cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL); 
     CookieHandler.setDefault(cookieManager); 

     // create rest adapter 
     restAdapter = new RestAdapter.Builder() 
      .setEndpoint(server_url) 
      .setConverter(new GsonConverter(new GsonBuilder() 
        .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") 
        .registerTypeAdapter(Date.class, new DateSerializer()) 
        .create())) 
      .setLogLevel(LogLevel.FULL) 
      .setLog(new ResponseInterceptor()) 
      .build(); 

     // create API 
     the1Api = restAdapter.create(The1Api.class); 
    } 
} 

The1Api.java

public interface The1Api { 
    /* Chat */ 

    public class PublicMessage { 
     String from_user; 
     String message; 
     Date time; 
     Integer microsecond; 
     Boolean in_1_percent; 
    } 
    public class PublicMessageList { 
     Integer last_message_id; 
     ArrayList<PublicMessage> messages; 
    } 

    @GET("/chat/get_public_messages/") 
    public PublicMessageList getPublicMessages(
      @Query("last_message_id") Integer last_message_id, // optional 
      @Query("since") Date since, // optional 
      @Query("max") Integer max // optional 
      ); 

    // ... 
} 

LoginActivity.java

public class LoginActivity extends Activity { 
    // ... 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     Crashlytics.start(this); 
     MyApplication.createRestAdapter(getString(R.string.server_url)); 
     setContentView(R.layout.activity_login); 
    } 

    @Override 
    protected void onPostCreate(Bundle savedInstanceState){ 
     super.onPostCreate(savedInstanceState); 

     Thread thread = new Thread(){ 
      @Override 
      public void run(){ 
       ArrayList<The1Api.PublicMessage> publicMessages = MyApplication.the1Api.getPublicMessages(null, null, null).messages; 
       for (The1Api.PublicMessage m : publicMessages){ 
        Log.d("The1", "[" + m.time.toString() + "] " + m.from_user + ": " + m.message); 
       } 
       // when the following line gets executed, my server receives a request including the date below, 
       // but the server does not understand the format of the date because it does not get serialized properly 
       MyApplication.the1Api.getPublicMessages(null, new Date(1000000000), null); 
      } 
     }; 
     thread.start(); 
    } 

    // ...  
} 

DateSerializer.java

class DateSerializer implements JsonSerializer<Date> { 
    @Override 
    public JsonElement serialize(Date arg0, Type arg1, JsonSerializationContext arg2) { 
     SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US); 
     return new JsonPrimitive(df.format(arg0)); 
    } 
} 

EDIT 2: Нет решения, как до сих пор, но в качестве обходного пути вы можете вручную преобразовать даты в другой формат перед его отправкой. В комментариях Kalel предложил преобразовать его в String, я преобразовал его в Long (количество секунд с UNIX-эпохи).

+0

Первый взгляд на 'SimpleDateFormat df = новый SimpleDateFormat (" yyyy-MM-dd'T'HH: mm: ssZ ", Locale.US);' и 'df.format (arg0)'. Если он отлично работает, перейдите к следующему шагу, чтобы определить свой пользовательский Сериализатор. Для получения дополнительной информации см. [SimpleDateFormat] (http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html) – Braj

+0

Когда я попытался отладить эти строки раньше, я заметил, что они были никогда не назывался - поэтому я попробовал заменить код вместо этого вместо RuntimeException. Однако, поскольку сериализатор никогда не получает вызов, который не может быть проблемой, даже если эти строки ошибочны, не так ли? – RevolutionTech

+0

Так что проблема в том, что сериализатор никогда не вызван. Пожалуйста, поправьте меня, если я ошибаюсь. – Braj

ответ

1

Вы все еще можете повторить эту проблему? Я вижу, что Gson сериализует и десериализует правильно. Возможно, это проблема с обновлением (я еще не использовал ее раньше), но, глядя на документы для GsonConverter, я не вижу причин, чтобы она делала что-либо, кроме делегирования, предоставленному в объекте Gson.

Вот SSCCE:

public class GsonDateDemo { 
    public static void main(String[] args) { 
    Gson gson = new GsonBuilder() 
     .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") 
     .registerTypeAdapter(Date.class, new DateSerializer()) 
     .create(); 
    Date d = new Date(1438806977000L); 

    System.out.println("Serializing "+d); 
    String json = gson.toJson(d); 
    System.out.println("JSON: "+json); 
    Date d2 = gson.fromJson(json, Date.class); 
    System.out.println("Deserialized: "+d2); 
    System.out.println("Equal? "+d.equals(d2)); 
    } 

    static class DateSerializer implements JsonSerializer<Date> { 
    @Override 
    public JsonElement serialize(Date arg0, Type arg1, JsonSerializationContext arg2) { 
     System.out.println("Serializer received "+arg0); 
     SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US); 
     return new JsonPrimitive(df.format(arg0)); 
    } 
    } 
} 

Это выходы:

Calling: local.GsonDateDemo.main[] 
Serializing Wed Aug 05 16:36:17 EDT 2015 
Serializer received Wed Aug 05 16:36:17 EDT 2015 
JSON: "2015-08-05T16:36:17-0400" 
Deserialized: Wed Aug 05 16:36:17 EDT 2015 
Equal? true 

Если вы можете изменить этот SSCCE использовать Дооснащение и посмотреть, если вы можете повторить провал, что путь.

+0

Я не работал над этим проектом уже некоторое время; Боюсь, я не смогу попробовать. Если снова столкнуться с подобной проблемой, я вернусь к этому. Возможно, кто-то еще, кто пережил эту проблему, сможет поделиться своими мыслями? – RevolutionTech