Estoy usando la biblioteca Retrofit para mis llamadas REST. La mayor parte de lo que he hecho ha sido fluido como la mantequilla, pero por alguna razón tengo problemas para convertir cadenas de marca de tiempo JSON en java.util.Date
objetos. El JSON que está entrando se ve así.
{
"date": "2013-07-16",
"created_at": "2013-07-16T22:52:36Z",
}
¿Cómo puedo decirle a Retrofit o Gson que convierta estas cadenas en java.util.Date objects
?
Respuestas:
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();
O el equivalente de 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)
Puede configurar su analizador Gson personalizado para que se actualice. Más aquí: Sitio web de Retrofit
Mire la respuesta de Ondreju para ver cómo implementar esto en la actualización 2.
fuente
ServiceGenerator
?2016-02-11T13:42:14.401Z
se deserializa a un objeto de fecha que es para13:42:14
en mi configuración regional.La respuesta de @ gderaco se actualizó a la actualización 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();
fuente
Así es como lo hice:
Cree la clase DateTime extendiendo Date y luego escriba un deserializador personalizado:
public class DateTime extends java.util.Date { public DateTime(long readLong) { super(readLong); } public DateTime(Date date) { super(date.getTime()); } }
Ahora, para la parte del deserializador donde registramos convertidores de fecha y fecha y hora:
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(); }
Y cuando cree su RestAdapter, haga lo siguiente:
new RestAdapter.Builder().setConverter(gsonWithDate());
Tu Foo debería verse así:
class Foo { Date date; DateTime created_at; }
fuente
return df.parse(json.getAsString());
along timeStamp = Long.parseLong(json.getAsString()); return new java.util.Date(timeStamp);
Gson puede manejar solo un formato de fecha y hora (los especificados en el constructor) más el iso8601 si no es posible analizar con un formato personalizado. Por lo tanto, una solución podría ser escribir su deserializador personalizado. Para solucionar tu problema definí:
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 + "]"; } }
con este deserializador:
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); } }
El último paso es crear una
Gson
instancia con el adaptador correcto: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); } }
Mi resultado:
Result: Foo [date=Tue Jul 16 00:00:00 CEST 2013, created_at=Tue Jul 16 22:52:36 CEST 2013]
fuente
Literalmente, si ya tiene un objeto Date con el nombre "created_at" en la clase que está creando, entonces es así de fácil:
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").create(); YourObject parsedObject1 = gson.fromJson(JsonStringYouGotSomehow, YourObject.class);
Y tu estas listo. no se necesita anulación complicada.
fuente
Puede definir dos nuevas clases como esta:
import java.util.Date; public class MyDate extends Date { }
y
import java.util.Date; public class CreatedAtDate extends Date { }
Tu POJO será así:
import MyDate; import CreatedAtDate; public class Foo { MyDate date; CreatedAtDate created_at; }
Finalmente configure su deserializador personalizado:
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; } }
y
GsonBuilder builder = new GsonBuilder(); builder.registerTypeAdapter(MyDate.class, new MyDateDeserializer());
fuente
Esto no responde directamente a la pregunta formulada, pero, en mi opinión, es el "estado del arte" si el codificador tiene total libertad para elegir cómo resolver el problema.
Primero que nada, no es la mejor solución usar java.util.Date. La razón es que esas clases no tuvieron un comportamiento ideal en algunos casos de esquina, por lo que cuando fueron reemplazadas por la clase Java Instant, etc., verifique la respuesta de Basil Bourque en esta pregunta SO: Creación de objetos Date en Kotlin para un nivel de API menor o igual a 16
Entonces usé la clase Instant de ThreeTenABP, y usando Kotlin, en Android:
fuente