2012-10-14 18 views
11

Próbuję użyć Gson do deserializacji tablicy json, ale obecnie otrzymuję JsonSyntaxException. Ciąg json został utworzony przez usługę sieci web MVC3 .NET przy użyciu JsonResult (co oznacza, nie jestem ręcznie tworzenia json, jest tworzony przez biblioteki, które wiem, aby pracować na kilku innych platformach).Gson: JsonSyntaxException na datę

To json:

[{"PostID":1,"StudentID":39,"StudentName":"Joe Blow", 
"Text":"Test message.","CreateDate":"\/Date(1350178408267)\/", 
"ModDate":"\/Date(1350178408267)\/","CommentCount":0}] 

Jest to kod:

public class Post { 
    public int PostID; 
    public int StudentID; 
    public String StudentName; 
    public String Text; 
    public Date CreateDate; 
    public Date ModDate; 

    public Post() { } 
} 

Type listOfPosts = new TypeToken<ArrayList<Post>>(){}.getType(); 
ArrayList<Post> posts = new Gson().fromJson(json, listOfPosts); 

Wyjątkiem mówi, że format daty jest nieprawidłowy:

com.google.gson.JsonSyntaxException: /Date(1350178408267)/ 

ktoś wie co się dzieje na?

Odpowiedz

17

Znalazłem odpowiedź here, ale uznałem za dziwne, że nie jest łatwiejszy sposób. Kilka innych bibliotek json, które używałem, obsługuje natywnie format json .NET. Byłem zaskoczony, gdy Gson tego nie zrobił. Musi być lepszy sposób. Jeśli ktoś o tym wie, opublikuj go tutaj. Mimo to, to było moje rozwiązanie:

Utworzono niestandardowy JsonDeserializer i zarejestrowałem go dla typu Date. W ten sposób Gson użyje mojego deserializera dla typu Date zamiast domyślnego. To samo można zrobić dla każdego innego typu, jeśli chcesz serializować/deserializować go w niestandardowy sposób.

public class JsonDateDeserializer implements JsonDeserializer<Date> { 
    public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
     String s = json.getAsJsonPrimitive().getAsString(); 
     long l = Long.parseLong(s.substring(6, s.length() - 2)); 
     Date d = new Date(l); 
     return d; 
    } 
} 

Potem, kiedy tworzę moją obiekt Gson:

Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new JsonDateDeserializer()).create(); 

Teraz moim celem gson będą zdolne do analizowania formatu daty .NET (w milisekundach od 1970).

+7

To jest właściwy sposób to zrobić. Biorąc pod uwagę, że Microsoft przygotował własny format dat, którego nikt inny nie używa, nie dziwi mnie, że Gson nie obsługuje go po wyjęciu z pudełka. Dlaczego, u licha, po prostu nie używają ISO-8601 jak zdrowi ludzie? – GreyBeardedGeek

+0

Nie jestem pewien, ale to, co naprawdę mnie zdezorientowało, to że korzystałem z innych bibliotek analizujących Json (na innych platformach innych niż Microsoft), które radzą sobie z tym dobrze. Gson był pierwszym, którego odkryłem, że nie poradził sobie z tym po wyjęciu z pudełka. – mtmurdock

+1

@GreyBeardedGeek: Nie ma * rozsądnego formatu datetime ISO-8601 * w JSON. W JSON nie ma formatu datetime; masz na myśli tylko zwykły ciąg znaków. Nie pamiętam dokładnie powodu (i nie mogę go już znaleźć), dlaczego go potrzebowali i dlaczego wybrali tę drogę, ale było to całkiem przekonujące. Może powinniśmy zapytać, dlaczego w JSON nie ma formatu datetime? I nie, naprawdę nie jestem fanem M $. – maaartinus

3

Serialize i Deserialize methoda. Zarejestrować to jako Adapter do GSON

JsonSerializer<Date> ser = new JsonSerializer<Date>() { 
@Override 
public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext 
     context) { 
return src == null ? null : new JsonPrimitive(src.getTime()); 
} 
}; 

JsonDeserializer<Date> deser = 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, ser) 
.registerTypeAdapter(Date.class, deser).create(); 
11

Innym rozwiązaniem jest użycie formatu ISO 8601. To musi być skonfigurowane na obu stronach Gson jako:

Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").create(); 

, a także po stronie serwera, np. dla ASP.NET MVC w Global.asax.cs pliku w następujący sposób:

JsonSerializerSettings serializerSettings = new JsonSerializerSettings(); 
serializerSettings.Converters.Add(new IsoDateTimeConverter()); 
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings = serializerSettings; 

Zaletą powyższego kodu jest to, że obsługuje zarówno serializacji i deserializacji, a tym samym umożliwia dwukierunkowe przesyłanie daty/czasu.

Uwaga: klasa IsoDateTimeConverter jest częścią JSON.NET library.

2

Rozwiązanie to działa na mnie za pomocą SqlDateTypeAdapter:

SqlDateTypeAdapter sqlAdapter = new SqlDateTypeAdapter(); 
Gson gson = new GsonBuilder() 
    .registerTypeAdapter(java.sql.Date.class, sqlAdapter) 
    .setDateFormat("yyyy-MM-dd") 
    .create(); 

Ref: https://stackoverflow.com/a/30398307/7308789

+0

To nie zadziałałoby w tym przypadku, ponieważ OP pyta o datę zapisaną jako epoka, a twoje rozwiązanie odnosi się do daty jako rrrr-MM-dd. – AlexM