Насколько я могу судить, 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-эпохи).
Первый взгляд на '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
Когда я попытался отладить эти строки раньше, я заметил, что они были никогда не назывался - поэтому я попробовал заменить код вместо этого вместо RuntimeException. Однако, поскольку сериализатор никогда не получает вызов, который не может быть проблемой, даже если эти строки ошибочны, не так ли? – RevolutionTech
Так что проблема в том, что сериализатор никогда не вызван. Пожалуйста, поправьте меня, если я ошибаюсь. – Braj