Po 4 godzinach nieustannych prób rozwiązania problemu postanowiłem zapytać tutaj, czy ktoś mógłby mi pomóc.
Problem polega na tym, że mój klient z Androidem, próbując deserializować dane odebrane z serwera, zgłasza wyjątek „Unparseable: 1302828677828”.
Chciałbym wiedzieć, czy można deserializować datę w formacie milisekund za pomocą Gson.
long
, a następnie programowo przekonwertować golong
na aDate
w swoim kodzie?Odpowiedzi:
Komentarz Alfonso:
źródło
.getAsJsonPrimitive()
można pominąć, aw przypadkuGson gson = new GsonBuilder().registerTypeAdapter(Date.class, (JsonDeserializer) (json, typeOfT, context) -> new Date(json.getAsLong())).create();
Napisałem ImprovedDateTypeAdapter na podstawie domyślnego DateTypeAdapter GSON, który obsługuje domyślny format dat i format znacznika czasu (długi).
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); } }
Aby z niego skorzystać:
// 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();
źródło
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();
źródło
Użyj poniższego fragmentu kodu, aby przekonwertować milisekundy na Date podczas przetwarzania 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();
źródło
Mam ten sam problem, gdy próbowałem deserializowania DateTime pole z Rest klienta z Androidem adnotacje bibliotece. Jako rozwiązanie stworzyłem niestandardowy GsonHttpMessageConverter
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()); } }
i zdefiniuj to w rest kliencie
@Rest(rootUrl = "http://192.168.1.1:8080", converters = {CustomGsonHttpMessageConverter.class}) public interface RestClient extends RestClientErrorHandling { ...
Mam nadzieję, że będzie to pomocne
źródło
Z jakiegoś powodu miałem błędy kompilacji w Intellij z powyższym kodem używającym anonimowej klasy; pracowała dla mnie lambda:
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(); }
źródło