90 votes

Rétrofit GSON sérialise la date de la chaîne json en java.util.date

J'utilise la bibliothèque Retrofit pour mes appels REST. La plupart de ce que j'ai fait s'est déroulé sans problème, mais pour une raison ou une autre, j'ai des difficultés à convertir les chaînes d'horodatage JSON en chaînes d'enregistrement. java.util.Date objets. Le JSON qui arrive ressemble à ça.

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

Comment puis-je dire à Retrofit ou Gson de convertir ces chaînes en java.util.Date objects ?

188voto

gderaco Points 185
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();

Ou l'équivalent en 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)

Vous pouvez configurer votre analyseur syntaxique Gson personnalisé pour le mettre à niveau. Plus d'informations ici : Site web de Retrofit

Regardez la réponse d'Ondreju pour voir comment mettre cela en œuvre dans le rétrofit 2.

92voto

Andrzej Purtak Points 921

La réponse de @gderaco a été mise à jour pour le rétrofit 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();

15voto

Kuanysh Raimbekov Points 150

Voici comment j'ai procédé :

Créez la classe DateTime en étendant Date, puis écrivez un désérialiseur personnalisé :

public class DateTime extends java.util.Date {

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

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

Passons maintenant à la partie désérialiseur où nous enregistrons les convertisseurs Date et DateTime :

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

Et lorsque vous créez votre RestAdapter, faites ce qui suit :

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

Votre Foo devrait ressembler à ceci :

class Foo {
    Date date;
    DateTime created_at;
}

8voto

giampaolo Points 3251

Gson ne peut gérer qu'un seul format de date (ceux spécifiés dans le constructeur) plus l'iso8601 si l'analyse avec le format personnalisé n'est pas possible. Donc, une solution pourrait être d'écrire votre propre désérialiseur. Pour résoudre votre problème, j'ai défini :

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

}

avec ce désérialiseur :

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

}

La dernière étape consiste à créer un Gson instance avec le bon adaptateur :

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

}

Mon résultat :

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

0voto

cpoole Points 336

Si vous avez déjà un objet Date avec le nom "created_at" dans la classe que vous créez, c'est très simple :

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

Et voilà, vous avez terminé. Pas besoin de surcharge compliquée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X