"Fecha no analizable: 1302828677828" tratando de deserializar con Gson una fecha en formato de milisegundos recibida del servidor

80

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.

Alfonso
fuente
¿Qué fecha / hora se supone que representa?
Squonk
¿No puede simplemente analizarlo como a long, y luego convertirlo mediante programación en longa Dateen su código?
aroth
11
Finalmente obtuve la solución: // Crea el objeto json que administrará la información recibida GsonBuilder builder = new GsonBuilder (); // Registrar un adaptador para administrar los tipos de fecha como valores largos builder.registerTypeAdapter (Date.class, new JsonDeserializer <Date> () {public Date deserialize (JsonElement json, Type typeOfT, JsonDeserializationContext context) arroja JsonParseException {return new Date (json .getAsJsonPrimitive (). getAsLong ());}}); Gson gson = constructor.create ();
Alfonso

Respuestas:

147

Comentario de Alfonso:

Finalmente obtuve la solución:

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

Gson gson = builder.create();
Peter O.
fuente
¡¡Muchas gracias por salvarme el tiempo !!
Chris Sim
problemas de zona horaria
CRONO
Gracias, esto también me ayudó. Aunque usé esto para Timestamp.
Feru
esto funciona para cada fecha que se pasa en milisegundos, no para pasar una regla para cada tipo de objetos analizados
Nather Webber
2
.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();
gmk57
2

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();
Simone Lai
fuente
2
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();
Ahmad Aghazadeh
fuente
1

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();
Chandra Sekhar
fuente
0

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

Vadim Zin4uk
fuente
0

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