Ich verwende die Retrofit-Bibliothek für meine REST-Aufrufe. Das meiste, was ich getan habe, war butterweich, aber aus irgendeinem Grund habe ich Probleme beim Konvertieren von JSON-Zeitstempelzeichenfolgen in java.util.Date
Objekte. Der JSON, der hereinkommt, sieht so aus.
{
"date": "2013-07-16",
"created_at": "2013-07-16T22:52:36Z",
}
Wie kann ich Retrofit oder Gson anweisen, diese Zeichenfolgen in zu konvertieren java.util.Date objects
?
Antworten:
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();
Oder das Kotlin-Äquivalent:
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)
Sie können Ihren benutzerdefinierten Gson-Parser auf Nachrüstung einstellen. Mehr hier: Nachrüst-Website
Sehen Sie sich die Antwort von Ondreju an, um zu sehen, wie dies in Retrofit 2 implementiert werden kann.
quelle
ServiceGenerator
?2016-02-11T13:42:14.401Z
wird zu einem Datumsobjekt deserialisiert, das für13:42:14
mein Gebietsschema bestimmt ist.@ gderacos Antwort auf Nachrüstung 2.0 aktualisiert:
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();
quelle
So habe ich es gemacht:
Erstellen Sie eine DateTime-Klasse, die Date erweitert, und schreiben Sie dann einen benutzerdefinierten Deserializer:
public class DateTime extends java.util.Date { public DateTime(long readLong) { super(readLong); } public DateTime(Date date) { super(date.getTime()); } }
Nun zum Deserializer-Teil, in dem wir sowohl Date- als auch DateTime-Konverter registrieren:
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(); }
Gehen Sie beim Erstellen Ihres RestAdapters wie folgt vor:
new RestAdapter.Builder().setConverter(gsonWithDate());
Dein Foo sollte so aussehen:
class Foo { Date date; DateTime created_at; }
quelle
return df.parse(json.getAsString());
zulong timeStamp = Long.parseLong(json.getAsString()); return new java.util.Date(timeStamp);
Gson kann nur ein Datum / Uhrzeit-Format (die im Builder angegebenen) sowie das iso8601 verarbeiten, wenn das Parsen mit einem benutzerdefinierten Format nicht möglich ist. Eine Lösung könnte also darin bestehen, Ihren benutzerdefinierten Deserializer zu schreiben. Um Ihr Problem zu lösen, habe ich definiert:
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 + "]"; } }
mit diesem Deserializer:
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); } }
Der letzte Schritt besteht darin, eine
Gson
Instanz mit dem richtigen Adapter zu erstellen :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); } }
Mein Ergebnis:
Result: Foo [date=Tue Jul 16 00:00:00 CEST 2013, created_at=Tue Jul 16 22:52:36 CEST 2013]
quelle
Wenn Sie in der Klasse, die Sie erstellen, bereits ein Date-Objekt mit dem Namen "created_at" haben, ist dies ganz einfach:
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").create(); YourObject parsedObject1 = gson.fromJson(JsonStringYouGotSomehow, YourObject.class);
Und du bist fertig. Kein kompliziertes Überschreiben erforderlich.
quelle
Sie können zwei neue Klassen wie folgt definieren:
import java.util.Date; public class MyDate extends Date { }
und
import java.util.Date; public class CreatedAtDate extends Date { }
Ihr POJO wird so aussehen:
import MyDate; import CreatedAtDate; public class Foo { MyDate date; CreatedAtDate created_at; }
Stellen Sie schließlich Ihren benutzerdefinierten Deserializer ein:
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; } }
und
GsonBuilder builder = new GsonBuilder(); builder.registerTypeAdapter(MyDate.class, new MyDateDeserializer());
quelle
Dies beantwortet die gestellte Frage nicht direkt, ist aber meiner Meinung nach der "Stand der Technik", wenn der Codierer die volle Wahlfreiheit bei der Lösung des Problems hat.
Erstens ist es nicht die beste Lösung, java.util.Date zu verwenden. Der Grund dafür ist, dass diese Klassen in einigen Eckfällen kein ideales Verhalten hatten. Wenn sie von der Java Instant-Klasse usw. abgelöst wurden, überprüfen Sie die Antwort von Basil Bourque in dieser SO-Frage: Erstellen von Datumsobjekten in Kotlin für API-Level kleiner oder gleich 16
Also habe ich die Instant-Klasse von ThreeTenABP und Kotlin unter Android verwendet:
quelle