2012-10-14 13 views
11

Sto tentando di utilizzare Gson per deserializzare un array JSON, ma attualmente sto ricevendo una JSONSyntaxException. La stringa json è stata creata da un servizio Web .NET MVC3 che utilizza JsonResult (ovvero, non sto creando manualmente il json, è stato creato da una libreria che so funzionare su molte altre piattaforme).Gson: JsonSyntaxException in data

Questa è la JSON:

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

Questo è il codice:

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); 

L'eccezione dice che il formato della data non è valida:

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

qualcuno che sa cosa sta succedendo sopra?

risposta

17

Ho trovato una risposta here ma ho trovato strano che non ci sia un modo più semplice. Diverse altre librerie json che ho usato supportano nativamente il formato .NET json. Sono rimasto sorpreso quando Gson non l'ha gestito. Ci deve essere un modo migliore. Se qualcuno ne conosce uno, per favore postalo qui. Tuttavia, questa era la mia soluzione:

Ho creato un JsonDeserializer personalizzato e l'ho registrato per il tipo Data. Facendo così, Gson userà il mio deserializzatore per il tipo Data invece del suo valore predefinito. Lo stesso può essere fatto per qualsiasi altro tipo se si desidera serializzare/deserializzare in modo personalizzato.

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; 
    } 
} 

Poi, quando sto creando il mio oggetto GSON:

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

Ora il mio oggetto GSON sarà in grado di analizzare il formato della data .NET (millis dal 1970).

+7

Questo è il modo corretto per farlo. Dato che Microsoft ha creato il proprio formato di data che nessun altro usa, non trovo sorprendente che Gson non lo supporti immediatamente. Perché mai non usano solo ISO-8601 come persone sane? – GreyBeardedGeek

+0

Non ne sono sicuro, ma quello che mi ha davvero confuso è che ho usato altre librerie di analisi di Json (su altre piattaforme non Microsoft) che gestiscono bene. Gson è stato il primo che ho trovato che non l'ha gestito fuori dagli schemi. – mtmurdock

+1

@GreyBeardedGeek: non esiste un formato * datetime ISO-8601 * sane in JSON. Non esiste affatto un formato datetime in JSON; quello che intendi è solo una stringa semplice. Non ricordo la ragione esatta (e non riesco a trovarla più) perché ne avevano bisogno e perché l'hanno scelta in questo modo, ma era abbastanza convincente. Forse dovremmo chiedere invece perché non c'è un formato datetime in JSON? E no, non sono davvero niente come un fan di M $. – maaartinus

3

Metodo serializzazione e deserializzazione. Registra questo come un adattatore per 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

Un'altra soluzione è quella di utilizzare il formato ISO 8601. Questo deve essere configurato su entrambi i lati Gson come:

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

e sul lato server, ad es. per ASP.NET MVC in Global.asax.cs di file, come segue:

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

Il vantaggio del codice di cui sopra è che gestisce sia la serializzazione e deserializzazione e permette in tal modo due trasmissione modo di date/orari.

Nota: la classe IsoDateTimeConverter fa parte di JSON.NET library.

2

questa soluzione funziona per me utilizzando SqlDateTypeAdapter:

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

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

+0

Questo non funzionerebbe in questo caso, poiché OP sta chiedendo una Data scritta come un'epoca, e la tua soluzione si riferisce alla data come aaaa-MM-gg. – AlexM