Java 从未调用日期的自定义gson反序列化程序

Java 从未调用日期的自定义gson反序列化程序,java,date,serialization,gson,retrofit,Java,Date,Serialization,Gson,Retrofit,据我所知,gson不会自动将java.util.Date对象序列化和反序列化为ISO字符串,例如“yyyy-MM-ddTHH:MM:ssZ”或“2014-04-15T18:22:00-05:00”。因此,为了使我能够在我的客户机(使用gson改造)和服务器之间正确地通信日期,我需要为gson指定日期格式。以下是我所做的: // code defining the creation of a RestAdapter // ... new GsonBuilder() .setDateForm

据我所知,gson不会自动将java.util.Date对象序列化和反序列化为ISO字符串,例如“yyyy-MM-ddTHH:MM:ssZ”或“2014-04-15T18:22:00-05:00”。因此,为了使我能够在我的客户机(使用gson改造)和服务器之间正确地通信日期,我需要为gson指定日期格式。以下是我所做的:

// code defining the creation of a RestAdapter
// ...
new GsonBuilder()
    .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
    .create()
添加.setDateFormat行足以让gson将时间戳字符串正确地反序列化到日期对象中。但是,它没有将日期对象序列化为时间戳字符串。因此,我假设必须创建一个自定义序列化程序,如下所示:

// 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));
    }
}
但当然,永远不会抛出RuntimeException

有人知道为什么我的序列化函数被忽略了吗?我想我在某个地方读到,对于某些类型,如果为超类定义了一个registerTypeAdapter,那么它将被忽略,但是由于这是java.util.Date,如果这是问题所在,我会感到困惑。我可能只是在做一些愚蠢的事情,但我可能对Date或gson不太了解,无法意识到这一点

编辑:提供了有关以下代码的更多上下文:

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);
    }
}
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
            );   

    // ...
}
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();
    }

    // ...    
}
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));
    }
}
1api.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);
    }
}
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
            );   

    // ...
}
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();
    }

    // ...    
}
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));
    }
}
公共接口API{
/*聊天*/
公共类公共消息{
来自用户的字符串;
字符串消息;
日期时间;
整数微秒;
布尔值,单位为1%;
}
公共类PublicMessageList{
整数last_message_id;
ArrayList消息;
}
@获取(“/chat/GET\u public\u messages/”)
PublicMessageList getPublicMessages(
@查询(“last\u message\u id”)整数last\u message\u id,//可选
@查询(“自”)日期自,//可选
@查询(“max”)整数max//可选
);   
// ...
}
LoginActivity.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);
    }
}
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
            );   

    // ...
}
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();
    }

    // ...    
}
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));
    }
}
公共类LoginActivity扩展活动{
// ...
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
Crashlytics.启动(此);
createRestAdapter(getString(R.string.server_url));
setContentView(R.layout.activity\u登录);
}
@凌驾
后期创建时受保护的空(捆绑包savedInstanceState){
super.onPostCreate(savedInstanceState);
线程线程=新线程(){
@凌驾
公开募捐{
ArrayList publicMessages=MyApplication.1API.getPublicMessages(null,null,null).messages;
for(1api.PublicMessage m:publicMessages){
Log.d(“The1”,“[”+m.time.toString()+“]”“+m.from_user+”:“+m.message”);
}
//当执行以下行时,我的服务器收到一个包含以下日期的请求,
//但是服务器不理解日期的格式,因为它没有正确序列化
MyApplication.1API.getPublicMessages(null,新日期(100000000),null);
}
};
thread.start();
}
// ...    
}
DateSerializer.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);
    }
}
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
            );   

    // ...
}
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();
    }

    // ...    
}
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));
    }
}
类DateSerializer实现JsonSerializer{ @凌驾 公共JsonElement序列化(日期arg0,类型arg1,JsonSerializationContext arg2){ SimpleDataFormat df=新的SimpleDataFormat(“yyyy-MM-dd'T'HH:MM:ssZ”,Locale.US); 返回新的JsonPrimitive(df.format(arg0)); } }
编辑2:目前还没有解决方案,但作为一种解决方法,您可以在发送日期之前手动将日期转换为其他格式。在Kalle建议将其转换为字符串的注释中,我将其转换为Long(自UNIX时代以来的秒数)。

您仍然能够复制此问题吗?我看到Gson正确地序列化和反序列化了。这可能是一个改装问题(我以前没有使用过),但查看文档,除了委托给
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));
    }
  }
}

如果可以,请修改此SSCCE以使用改型,并查看是否可以通过这种方式复制故障。

gson中的问题,当我们尝试使用after call
setDateFormat
反序列化时,自定义
DateDesializer
不调用


因此,在反序列化时,不要调用
setDateFormat
;)

首先看一下
SimpleDateFormat df=newsimpledateformat(“yyyy-MM-dd'T'HH:MM:ssZ”,Locale.US)
df.format(arg0)
。如果它工作正常,则转到下一步定义自定义序列化程序。要了解更多信息,请查看我之前尝试调试这些行时,我注意到它们从未被调用-因此我尝试用抛出RuntimeException替换代码。然而,由于序列化程序从未被调用,即使这些行是错误的,也不会是问题,是吗?所以问题是序列化程序从未被调用。如果我错了,请纠正我。你能发布你的完整代码吗。您使用的是什么JSON?返回的Gson是如何使用的?谢谢Kalle,应该有用!在与该项目的其他一位工程师讨论之后,我们决定将日期时间传递为long(自UNIX纪元以来的秒数),这似乎对我们有用。因为这只是一个解决办法,但我会留下问题,以防翻新/Gson得到更新(我不知道谁该负责);恐怕我不能试一试。如果我再次遇到类似的问题,我会回到这个问题上来。也许其他经历过这个问题的人能够分享他们的想法?