package com.sap.pto.services.util;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Date;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
import org.joda.time.DateTime;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
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;
@Provider
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@SuppressWarnings("nls")
public class GsonMessageBodyHandler<T> implements MessageBodyWriter<T>, MessageBodyReader<T> {
private static ThreadLocal<Boolean> skipDataProtection = new ThreadLocal<Boolean>();
public GsonMessageBodyHandler() {
}
private GsonBuilder getGson() {
GsonBuilder gson = new GsonBuilder();
gson.setDateFormat("yyyy-MM-dd'T'HH:mm:ss Z");
gson.registerTypeAdapter(DateTime.class, new DateTimeTypeConverter());
gson.setPrettyPrinting();
if (skipDataProtection.get() == null || !skipDataProtection.get()) {
gson.addSerializationExclusionStrategy(new GsonExclusionStrategy());
}
return gson;
}
@Override
public long getSize(T t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return -1;
}
@Override
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return true;
}
@Override
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return true;
}
@Override
public T readFrom(Class<T> type, Type genericType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
Reader entityReader = new InputStreamReader(entityStream, "UTF-8");
Type targetType;
if (Collection.class.isAssignableFrom(type)) {
targetType = genericType;
} else {
targetType = type;
}
return getGson().create().<T>fromJson(entityReader, targetType);
}
@Override
public void writeTo(T t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
// convert all except Strings
if (!String.class.isAssignableFrom(type)) {
entityStream.write(getGson().create().toJson(t).getBytes("UTF-8"));
} else {
entityStream.write(((String) t).getBytes("UTF-8"));
}
}
public static void setSkipDataProtection(boolean status) {
skipDataProtection.set(status);
}
private static class DateTimeTypeConverter implements JsonSerializer<DateTime>, JsonDeserializer<DateTime> {
@Override
public JsonElement serialize(DateTime src, Type srcType, JsonSerializationContext context) {
return new JsonPrimitive(src.toString());
}
@Override
public DateTime deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
try {
return new DateTime(json.getAsString());
} catch (IllegalArgumentException e) {
// could also be a java.util.Date
Date date = context.deserialize(json, Date.class);
return new DateTime(date);
}
}
}
private static class GsonExclusionStrategy implements ExclusionStrategy {
@Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
@Override
public boolean shouldSkipField(FieldAttributes field) {
if (field.getAnnotation(JsonIgnore.class) != null) {
return true;
} else {
return false;
}
}
}
}