/** * Copyright 2005-2014 Restlet * * The contents of this file are subject to the terms of one of the following * open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can * select the license that you prefer but you may not use this file except in * compliance with one of these Licenses. * * You can obtain a copy of the Apache 2.0 license at * http://www.opensource.org/licenses/apache-2.0 * * You can obtain a copy of the EPL 1.0 license at * http://www.opensource.org/licenses/eclipse-1.0 * * See the Licenses for the specific language governing permissions and * limitations under the Licenses. * * Alternatively, you can obtain a royalty free commercial license with less * limitations, transferable or non-transferable, directly at * http://restlet.com/products/restlet-framework * * Restlet is a registered trademark of Restlet S.A.S. */ package org.restlet.ext.gson; import java.io.IOException; import java.io.Writer; import java.lang.reflect.Type; import java.text.DateFormat; import java.util.Date; import org.joda.time.DateTime; import org.restlet.data.MediaType; import org.restlet.representation.Representation; import org.restlet.representation.WriterRepresentation; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; /** * Representation based on a JSON document. JSON stands for JavaScript Object * Notation and is a lightweight data-interchange format. * * @author Neal Mi * @see <a href="http://code.google.com/p/google-gson/">Gson project</a> */ public class GsonRepresentation<T> extends WriterRepresentation { /** * Custom deserializer for {@link Date} instances. * * @author Neal Mi. */ private class ISODateDeserializer implements JsonDeserializer<Date> { public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return new DateTime(json.getAsJsonPrimitive().getAsString()) .toDate(); } } /** * Custom serializer for {@link Date} instances. * * @author Neal Mi. */ private class ISODateSerializer implements JsonSerializer<Date> { public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) { DateTime dt = new DateTime(src); // DateTime dtz = dt.withZone(DateTimeZone.forOffsetHours(-8)); return new JsonPrimitive(dt.toString()); } } /** The modifiable Gson builder. */ private GsonBuilder builder; /** The JSON representation to parse. */ private Representation jsonRepresentation; /** The (parsed) object to format. */ private T object; /** The object class to instantiate. */ private Class<T> objectClass; /** * Constructor. * * @param representation * The representation to parse. * @param objectClass * The object class to instantiate. */ public GsonRepresentation(Representation representation, Class<T> objectClass) { super(representation.getMediaType()); this.object = null; this.objectClass = objectClass; this.jsonRepresentation = representation; this.builder = null; } /** * Constructor for the JSON media type. * * @param object * The object to format. */ @SuppressWarnings("unchecked") public GsonRepresentation(T object) { super(MediaType.APPLICATION_JSON); this.object = object; this.objectClass = ((Class<T>) ((object == null) ? null : object .getClass())); this.jsonRepresentation = null; this.builder = null; } /** * Returns a new instance of the builder for Gson instances. * * @return a new instance of builder for Gson instances. */ protected GsonBuilder createBuilder() { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setDateFormat(DateFormat.FULL); return gsonBuilder; } /** * Returns the builder for Gson instances. * * @return The builder for Gson instances. */ public GsonBuilder getBuilder() { if (builder == null) { builder = createBuilder().registerTypeAdapter(Date.class, new ISODateSerializer()).registerTypeAdapter(Date.class, new ISODateDeserializer()); } return builder; } /** * Returns the wrapped object, deserializing the representation with Gson if * necessary. * * @return The wrapped object. * @throws IOException */ public T getObject() throws IOException { T result = null; if (this.object != null) { result = this.object; } else if (this.jsonRepresentation != null) { Gson gson = getBuilder().create(); result = gson.fromJson( new JsonReader(jsonRepresentation.getReader()), this.objectClass); } return result; } /** * Returns the object class to instantiate. * * @return The object class to instantiate. */ public Class<T> getObjectClass() { return objectClass; } /** * Sets the Gson builder. * * @param builder * The Gson builder. */ public void setBuilder(GsonBuilder builder) { this.builder = builder; } /** * Sets the object to format. * * @param object * The object to format. */ public void setObject(T object) { this.object = object; } /** * Sets the object class to instantiate. * * @param objectClass * The object class to instantiate. */ public void setObjectClass(Class<T> objectClass) { this.objectClass = objectClass; } @Override public void write(Writer writer) throws IOException { if (jsonRepresentation != null) { jsonRepresentation.write(writer); } else { Gson gson = getBuilder().create(); gson.toJson(object, objectClass, new JsonWriter(writer)); } } }