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

Ik gebruik de Retrofit-bibliotheek voor mijn REST-aanroepen. Het meeste van wat ik heb gedaan is soepel verlopen, maar om de een of andere reden heb ik problemen met het converteren van JSON-tijdstempelreeksen naar java.util.Date-objecten. De JSON die binnenkomt ziet er als volgt uit.

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

Hoe kan ik Retrofit of Gson vertellen deze strings om te zetten in java.util.Date objects?


Antwoord 1, autoriteit 100%

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

Of het Kotlin-equivalent:

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)

U kunt uw aangepaste Gson-parser zo instellen dat deze achteraf wordt aangepast. Meer hier: Retrofit-website

Kijk naar de reactie van Ondreju om te zien hoe je dit in retrofit 2 kunt implementeren.


Antwoord 2, autoriteit 50%

@gderaco’s antwoord geüpdatet om 2.0 te retrofitten:

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

Antwoord 3, autoriteit 8%

Hier is hoe ik het deed:

Maak een DateTime-klasse die Date verlengt en schrijf vervolgens een aangepaste deserializer:

public class DateTime extends java.util.Date {
    public DateTime(long readLong) {
        super(readLong);
    }
    public DateTime(Date date) {
        super(date.getTime());
    }       
}

Nu voor het deserializer-gedeelte waar we zowel Date- als DateTime-converters registreren:

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

En wanneer u uw RestAdapter maakt, doet u het volgende:

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

Uw Foo zou er zo uit moeten zien:

class Foo {
    Date date;
    DateTime created_at;
}

Antwoord 4, autoriteit 4%

Gson kan slechts één datum/tijd-formaat aan (die gespecificeerd in builder) plus de iso8601 als parseren met een aangepast formaat niet mogelijk is. Een oplossing zou dus kunnen zijn om uw aangepaste deserializer te schrijven. Om je probleem op te lossen heb ik het volgende gedefinieerd:

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 + "]";
    }
}

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

De laatste stap is het maken van een Gson-instantie met de juiste adapter:

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

Mijn resultaat:

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

Antwoord 5

Heel letterlijk als je al een Date-object hebt met de naam “created_at” in de klasse die je aan het maken bent, dan is het zo eenvoudig:

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

En je bent klaar. geen ingewikkelde overschrijving nodig.

Other episodes