改造 GSON 将日期从 json 字符串序列化为 java.util.date

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18473011/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 01:55:24  来源:igfitidea点击:

Retrofit GSON serialize Date from json string into java.util.date

javaandroidjsongsonretrofit

提问by jpotts18

I am using the Retrofit library for my REST calls. Most of what I have done has been smooth as butter but for some reason I am having issues converting JSON timestamp strings into java.util.Dateobjects. The JSON that is coming in looks like this.

我正在使用 Retrofit 库进行 REST 调用。我所做的大部分事情都像黄油一样顺利,但出于某种原因,我在将 JSON 时间戳字符串转换为java.util.Date对象时遇到了问题。传入的 JSON 如下所示。

{
    "date": "2013-07-16",
    "created_at": "2013-07-16T22:52:36Z",
} 

How can I tell Retrofit or Gson to convert these strings into java.util.Date objects?

我如何告诉 Retrofit 或 Gson 将这些字符串转换为java.util.Date objects?

采纳答案by gderaco

Gson gson = new GsonBuilder()
    .setDateFormat("yyyy-MM-dd'T'HH:mm:ss")
    .create();

RestAdapter restAdapter = new RestAdapter.Builder()
    .setEndpoint(API_BASE_URL)
    .setConverter(new GsonConverter.create(gson))
    .build();

Or the Kotlin equivalent:

或 Kotlin 等价物:

val gson = GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss").create()
RestAdapter restAdapter = Retrofit.Builder()
    .baseUrl(API_BASE_URL)
    .addConverterFactory(GsonConverterFactory.create(gson))
    .build()
    .create(T::class.java)

You can set your customized Gson parser to retrofit. More here: Retrofit Website

您可以将自定义的 Gson 解析器设置为改造。更多信息:改造网站

Look at Ondreju's response to see how to implement this in retrofit 2.

查看 Ondreju 的回复,了解如何在改造 2 中实现这一点。

回答by giampaolo

Gson can handle only one datetime format (those specified in builder) plus the iso8601 if parsing with custom format is not possible. So, a solution could be to write your custom deserializer. To solve your problem I defined:

如果无法使用自定义格式进行解析,Gson 只能处理一种日期时间格式(在 builder 中指定的格式)和 iso8601。因此,解决方案可能是编写您的自定义解串器。为了解决您的问题,我定义了:

package stackoverflow.questions.q18473011;

import java.util.Date;

public class Foo {

    Date date;
    Date created_at;

    public Foo(Date date, Date created_at){
       this.date = date;
       this.created_at = created_at;
    }

    @Override
    public String toString() {
       return "Foo [date=" + date + ", created_at=" + created_at + "]";
    }

}

with this deserializer:

使用这个解串器:

package stackoverflow.questions.q18473011;

import java.lang.reflect.Type;
import java.text.*;
import java.util.Date;

import com.google.gson.*;

public class FooDeserializer implements JsonDeserializer<Foo> {

     public Foo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {

        String a = json.getAsJsonObject().get("date").getAsString();
        String b = json.getAsJsonObject().get("created_at").getAsString();

        SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat sdfDateWithTime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");

        Date date, created;
        try {
           date = sdfDate.parse(a);
           created = sdfDateWithTime.parse(b);
        } catch (ParseException e) {
           throw new RuntimeException(e);
        }

        return new Foo(date, created);
    }

}

Final step is to create a Gsoninstance with right adapter:

最后一步是Gson使用正确的适配器创建一个实例:

package stackoverflow.questions.q18473011;

import com.google.gson.*;

public class Question {

    /**
     * @param args
     */
    public static void main(String[] args) {
      String s = "{ \"date\": \"2013-07-16\",    \"created_at\": \"2013-07-16T22:52:36Z\"}";


      GsonBuilder builder = new GsonBuilder();
      builder.registerTypeAdapter(Foo.class, new FooDeserializer());

      Gson gson = builder.create();
      Foo myObject = gson.fromJson(s, Foo.class);

      System.out.println("Result: "+myObject);
    }

}

My result:

我的结果:

Result: Foo [date=Tue Jul 16 00:00:00 CEST 2013, created_at=Tue Jul 16 22:52:36 CEST 2013]

回答by Kuanysh Raimbekov

Here is how I did it:

这是我如何做到的:

Create DateTime class extending Date and then write a custom deserializer:

创建扩展 Date 的 DateTime 类,然后编写自定义反序列化器:

public class DateTime extends java.util.Date {

    public DateTime(long readLong) {
        super(readLong);
    }

    public DateTime(Date date) {
        super(date.getTime());
    }       
}

Now for the deserializer part where we register both Date and DateTime converters:

现在是我们注册日期和日期时间转换器的解串器部分:

public static Gson gsonWithDate(){
    final GsonBuilder builder = new GsonBuilder();

    builder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {  

        final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");  
        @Override  
        public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {  
            try {  
                return df.parse(json.getAsString());  
            } catch (final java.text.ParseException e) {  
                e.printStackTrace();  
                return null;  
            }  
        }
    });

    builder.registerTypeAdapter(DateTime.class, new JsonDeserializer<DateTime>() {  

        final DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
        @Override  
        public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {  
            try {  
                return new DateTime(df.parse(json.getAsString()));  
            } catch (final java.text.ParseException e) {
                e.printStackTrace();  
                return null;  
            }  
        }
    });

    return builder.create();
}

And when you create your RestAdapter, do the following:

创建 RestAdapter 时,请执行以下操作:

new RestAdapter.Builder().setConverter(gsonWithDate());

Your Foo should look like this:

你的 Foo 应该是这样的:

class Foo {
    Date date;
    DateTime created_at;
}

回答by cpoole

Quite literally if you already have an Date object with the name "created_at" in the class you are creating then it is this easy:

从字面上看,如果您在创建的类中已经有一个名为“created_at”的 Date 对象,那么这很简单:

Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").create();
YourObject parsedObject1 = gson.fromJson(JsonStringYouGotSomehow, YourObject.class);

And you're done. no complicated overriding needed.

你已经完成了。不需要复杂的覆盖。

回答by shiami

You can define two new classes like this:

您可以像这样定义两个新类:

import java.util.Date;

public class MyDate extends Date {
}

and

import java.util.Date;

public class CreatedAtDate extends Date {
}

Your POJO will be like this:

你的 POJO 将是这样的:

import MyDate;
import CreatedAtDate;

public class Foo {
    MyDate date;
    CreatedAtDate created_at;
}

Finally set your custom deserializer:

最后设置您的自定义解串器:

public class MyDateDeserializer implements JsonDeserializer<Date> {

    public static final SimpleDateFormat sServerDateDateFormat = new SimpleDateFormat("yyyy-MM-dd");

    @Override
    public MyDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
         if (json != null) {
            final String jsonString = json.getAsString();
            try {
                return (MyDate) sServerDateDateFormat.parse(jsonString);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}

and

GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(MyDate.class, new MyDateDeserializer());

回答by Andrzej Purtak

@gderaco's answer updated to retrofit 2.0:

@gderaco 的答案更新为改造 2.0:

Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss")
.create();

Retrofit retrofitAdapter = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();