Advertisements

Parsing .NET Json dates using Gson

I recently ran into a peculiar problem while writing an Android app the connects to a Json web service built on Microsoft’s .NET MVC3 platform. When I attempted to parse the Json using Google’s Gson library it threw a JsonParseException. Upon further examination I learned a few things about Json date formats, and how to extend the parsing capabilities of Gson.

Json Dates

Oddly enough, the Json standard doesn’t define a format for dates. In fact it doesn’t say anything about dates at all. As it would turn out, as long as people have been sending dates via json, they’ve been doing it whatever way they saw fit. This means that Json dates are nothing more than strings, and that the serializer and the deserializer must agree on a date format before transmitting or they will likely fail.

So how do we keep it straight? Most rational developers just use some existing date format standard such as ISO-8601. However, not everyone is rational. Microsoft, as usual, decided that rather than conforming to some existing format they would create their own. Granted, usually when they do this kind of thing they’ve got a few good reasons, but it does make compatibility an issue.

So what is Microsoft’s format? It looks something like this:

"\/Date(123456789)\/"

What you’re looking at is the milliseconds since the epoch (1970) wrapped in some fluff so it can be differentiated from a numeric type. Its actually a clever piece of text but, without getting into the technical details, it still presents an issue because Gson doesn’t know how to parse this.

Customizing Gson

Luckily, Google decided to make Gson flexible and “teachable”. If you ever run into this or any other strange formatting issue you can register a custom deserializer for your Gson object capable of reading any custom format. To do this you will need to create an object that implements the JsonDeserializer interface.

public static class DotNetDateDeserializer implements JsonDeserializer {
   public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
      if (json.isJsonNull())
         return null;

      String s = json.getAsJsonPrimitive().getAsString();
      long l = Long.parseLong(s.substring(6, s.length() - 2));
      Date d = new Date(l);
      return d; 
   } 
}

Now that we have a class capable of reading Microsoft’s Json date format, lets use it.

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

Take a look of the second line of this code. Here we are assigning our custom deserializer to the Date class. Now if we pass try to parse a json string containing a .NET formatted date, gson will know exactly what to do with it.

Custom Json Types

This same pattern can followed for any class. If you have a class that you want to represent as a single value in Json, you can create a custom deserializer for it.

For example, lets say you want to use css style color notation in json (like #FF0000 for red). Gson probably won’t be able to parse that on its own, but you can create a custom deserializer:

public class Color {
   int value
   public Color(int value) {
      this.value = value
   }
}

public static class ColorDeserializer implements JsonDeserializer {
   public Color deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
      if (json.isJsonNull())
         return null;

      String s = json.getAsJsonPrimitive().getAsString();
      int value = Integer.parseInt(s.substring(1, s.length() - 1), 16); // don't forget the radix!!
      Color c = new Color(value);
      return c; 
   } 
}

Using this code, you’ll be able to parse #00FF00 (Green) into a Color object.

Hope you find this as useful as I have.

Advertisements