Después de 4 horas sin parar tratando de resolver el problema, he decidido preguntar aquí si alguien podría ayudarme.
El problema es que mi cliente de Android cuando intenta deserializar los datos recibidos de un servidor lanza la excepción "Unparseable: 1302828677828".
Me gustaría saber si es posible deserializar una fecha en formato de milisegundos usando Gson.
long
, y luego convertirlo mediante programación enlong
aDate
en su código?Respuestas:
Comentario de Alfonso:
fuente
.getAsJsonPrimitive()
se puede omitir, y con Java 8 lambdas es aún más corto:Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, (JsonDeserializer) (json, typeOfT, context) -> new Date(json.getAsLong())).create();
Escribí un ImprovedDateTypeAdapter basado en el DateTypeAdapter predeterminado de GSON que admite el formato de fechas predeterminado y el formato de marca de tiempo (largo).
import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapterFactory; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; import java.io.IOException; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.TimeZone; public final class ImprovedDateTypeAdapter extends TypeAdapter<Date> { public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() { public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { @SuppressWarnings("unchecked") TypeAdapter<T> typeAdapter = (TypeAdapter<T>) ((typeToken.getRawType() == Date.class) ? new ImprovedDateTypeAdapter() : null); return typeAdapter; } }; private final DateFormat enUsFormat; private final DateFormat localFormat; private final DateFormat iso8601Format; public ImprovedDateTypeAdapter() { this.enUsFormat = DateFormat.getDateTimeInstance(2, 2, Locale.US); this.localFormat = DateFormat.getDateTimeInstance(2, 2); this.iso8601Format = buildIso8601Format(); } private static DateFormat buildIso8601Format() { DateFormat iso8601Format = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC")); return iso8601Format; } public Date read(JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { in.nextNull(); return null; } return deserializeToDate(in.nextString()); } private synchronized Date deserializeToDate(String json) { try { return new Date(Long.parseLong(json)); } catch (Exception e) { try { return this.localFormat.parse(json); } catch (ParseException e1) { try { return this.enUsFormat.parse(json); } catch (ParseException e2) { try { return this.iso8601Format.parse(json); } catch (ParseException e3) { throw new JsonSyntaxException(json, e3); } } } } } public synchronized void write(JsonWriter out, Date value) throws IOException { if (value == null) { out.nullValue(); return; } String dateFormatAsString = this.enUsFormat.format(value); out.value(dateFormatAsString); } }
Para usarlo:
// Creates the json object which will manage the information received GsonBuilder builder = new GsonBuilder(); // Register an adapter to manage the date types as long values builder.registerTypeAdapter(Date.class, new ImprovedDateTypeAdapter()); Gson gson = builder.create();
fuente
JsonSerializer<Date> serializer= new JsonSerializer<Date>() { @Override public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) { return src == null ? null : new JsonPrimitive(src.getTime()); } }; JsonDeserializer<Date> deserializer= new JsonDeserializer<Date>() { @Override public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return json == null ? null : new Date(json.getAsLong()); } }; Gson gson = new GsonBuilder() .registerTypeAdapter(Date.class, serializer) .registerTypeAdapter(Date.class, deserializer).create();
fuente
Use el siguiente fragmento para convertir milisegundos a fecha mientras procesa JSON.
GsonBuilder gsonBuilder = new GsonBuilder(); // Adapter to convert long values to date types gsonBuilder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() { public Date deserialize(JsonElement jsonElement, Type typeOfObj, JsonDeserializationContext context) throws JsonParseException { //Converting milliseconds to current Date. (instead of 1970) return new Date(jsonElement.getAsLong() * 1000); } }); Gson gson = gsonBuilder.setPrettyPrinting().create();
fuente
Tengo el mismo problema cuando intenté deserializar el campo DateTime con el cliente Rest de la biblioteca de anotaciones de Android . Como solución, he creado GsonHttpMessageConverter personalizado
public class CustomGsonHttpMessageConverter extends GsonHttpMessageConverter { public CustomGsonHttpMessageConverter() { // Creates the json object which will manage the information received GsonBuilder builder = new GsonBuilder(); // Register an adapter to manage the date types as long values builder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() { public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return new Date(json.getAsJsonPrimitive().getAsLong()); } }); setGson(builder.create()); } }
y definirlo en reposo cliente
@Rest(rootUrl = "http://192.168.1.1:8080", converters = {CustomGsonHttpMessageConverter.class}) public interface RestClient extends RestClientErrorHandling { ...
Espero que sea util
fuente
Por alguna razón, tuve errores de compilación en Intellij con el código anterior usando una clase anónima; una lambda funcionó para mí:
private static Gson buildGson(){ // Deserialize longs as Dates final JsonDeserializer<Date> dateDeserializer = (json, type, context) -> json == null ? null : new Date(json.getAsLong()); return new GsonBuilder().registerTypeAdapter(Date.class, dateDeserializer).create(); }
fuente