package br.com.caelum.vraptor.deserialization.gson;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import javax.servlet.http.HttpServletRequest;
import net.vidageek.mirror.dsl.Mirror;
import org.junit.Before;
import org.junit.Test;
import br.com.caelum.vraptor.core.Localization;
import br.com.caelum.vraptor.http.ParameterNameProvider;
import br.com.caelum.vraptor.resource.DefaultResourceClass;
import br.com.caelum.vraptor.resource.DefaultResourceMethod;
import br.com.caelum.vraptor.resource.ResourceClass;
import br.com.caelum.vraptor.resource.ResourceMethod;
import br.com.caelum.vraptor.serialization.gson.adapters.CalendarDeserializer;
import br.com.caelum.vraptor.util.ISO8601Util;
import br.com.caelum.vraptor.view.GenericController;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
public class GsonDeserializerTest {
private GsonDeserialization deserializer;
private ResourceMethod bark;
private ParameterNameProvider provider;
private Localization localization;
private ResourceMethod jump;
private DefaultResourceMethod woof;
private DefaultResourceMethod dropDead;
private DefaultResourceMethod adopt;
private DefaultResourceMethod sell;
private HttpServletRequest request;
@Before
public void setUp() throws Exception {
provider = mock(ParameterNameProvider.class);
localization = mock(Localization.class);
request = mock(HttpServletRequest.class);
when(localization.getLocale()).thenReturn(new Locale("pt", "BR"));
List<JsonDeserializer> deserializers = new ArrayList<JsonDeserializer>();
CalendarDeserializer calendarDeserializer = new CalendarDeserializer(localization);
deserializers.add(calendarDeserializer);
deserializer = new GsonDeserialization(provider, new DefaultJsonDeserializers(deserializers), request);
DefaultResourceClass resourceClass = new DefaultResourceClass(DogController.class);
woof = new DefaultResourceMethod(resourceClass, DogController.class.getDeclaredMethod("woof"));
bark = new DefaultResourceMethod(resourceClass, DogController.class.getDeclaredMethod("bark", Dog.class));
jump = new DefaultResourceMethod(resourceClass, DogController.class.getDeclaredMethod("jump", Dog.class,
Integer.class));
dropDead = new DefaultResourceMethod(resourceClass, DogController.class.getDeclaredMethod("dropDead",
Integer.class, Dog.class));
adopt = new DefaultResourceMethod(resourceClass, DogController.class.getDeclaredMethod("adopt",
List.class));
sell = new DefaultResourceMethod(resourceClass, DogController.class.getDeclaredMethod("sell",
List.class, String.class));
}
static class Dog {
private String name;
private Integer age;
private Calendar birthday;
@Override
public String toString() {
return "Dog [name=" + name + ", age=" + age + ", birthday="
+ birthday + "]";
}
}
static class ExtGenericController extends GenericController<Dog>{
}
static class DogController {
public void woof() {
}
public void bark(Dog dog) {
}
public void jump(Dog dog, Integer times) {
}
public void dropDead(Integer times, Dog dog) {
}
public void adopt(List<Dog> dogs) {
}
public void sell(List<Dog> dogs, String customer) {
}
}
private class DogDeserializer implements JsonDeserializer<Dog> {
public Dog deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
Dog dog = new Dog();
dog.name = "Renan";
dog.age = 25;
return dog;
}
}
@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptMethodsWithoutArguments() throws Exception {
deserializer.deserialize(new ByteArrayInputStream(new byte[0]), woof);
}
@Test
public void shouldBeAbleToDeserializeADog() throws Exception {
InputStream stream = new ByteArrayInputStream("{'dog':{'name':'Brutus','age':7}}".getBytes());
when(provider.parameterNamesFor(bark.getMethod())).thenReturn(new String[] { "dog" });
Object[] deserialized = deserializer.deserialize(stream, bark);
assertThat(deserialized.length, is(1));
assertThat(deserialized[0], is(instanceOf(Dog.class)));
Dog dog = (Dog) deserialized[0];
assertThat(dog.name, is("Brutus"));
assertThat(dog.age, is(7));
}
@Test
public void shouldBeAbleToDeserializeAListOfDogs() throws Exception {
String jsonArrayOfDogs = "{'dogs': [{'name':'Brutus','age':7}, {'name':'Snoop','age':10}] }";
InputStream stream = new ByteArrayInputStream(jsonArrayOfDogs.getBytes());
when(provider.parameterNamesFor(adopt.getMethod())).thenReturn(new String[] { "dogs" });
Object[] deserialized = deserializer.deserialize(stream, adopt);
assertThat(deserialized.length, is(1));
assertThat(deserialized[0], is(instanceOf(List.class)));
List<Dog> dogs = (List<Dog>) deserialized[0];
assertThat(dogs.size(), is(2));
assertThat(dogs.get(0).name, is("Brutus"));
assertThat(dogs.get(0).age, is(7));
assertThat(dogs.get(1).name, is("Snoop"));
assertThat(dogs.get(1).age, is(10));
}
@Test
public void shouldBeAbleToDeserializeAListOfDogsWithNoRoot() throws Exception {
String jsonArrayOfDogs = "[{'name':'Brutus','age':7}, {'name':'Snoop','age':10}]";
InputStream stream = new ByteArrayInputStream(jsonArrayOfDogs.getBytes());
when(provider.parameterNamesFor(adopt.getMethod())).thenReturn(new String[] { "dogs" });
Object[] deserialized = deserializer.deserialize(stream, adopt);
assertThat(deserialized.length, is(1));
assertThat(deserialized[0], is(instanceOf(List.class)));
List<Dog> dogs = (List<Dog>) deserialized[0];
assertThat(dogs.size(), is(2));
assertThat(dogs.get(0).name, is("Brutus"));
assertThat(dogs.get(0).age, is(7));
assertThat(dogs.get(1).name, is("Snoop"));
assertThat(dogs.get(1).age, is(10));
}
@Test
public void shouldBeAbleToDeserializeAListOfDogsWhenMethodHasMoreThenOneParameter() throws Exception {
String jsonArrayOfDogs = "{dogs: [{'name':'Brutus','age':7}, {'name':'Snoop','age':10}], customer: 'Me'}";
InputStream stream = new ByteArrayInputStream(jsonArrayOfDogs.getBytes());
when(provider.parameterNamesFor(sell.getMethod())).thenReturn(new String[] { "dogs", "customer" });
Object[] deserialized = deserializer.deserialize(stream, sell);
assertThat(deserialized.length, is(2));
assertThat(deserialized[0], is(instanceOf(List.class)));
List<Dog> dogs = (List<Dog>) deserialized[0];
assertThat(dogs.size(), is(2));
assertThat(dogs.get(0).name, is("Brutus"));
assertThat(dogs.get(0).age, is(7));
assertThat(dogs.get(1).name, is("Snoop"));
assertThat(dogs.get(1).age, is(10));
String customer = (String) deserialized[1];
assertThat(customer, is("Me"));
}
@Test
public void shouldBeAbleToDeserializeADogWithoutRoot() {
InputStream stream = new ByteArrayInputStream("{'name':'Brutus','age':7}".getBytes());
when(provider.parameterNamesFor(bark.getMethod())).thenReturn(new String[] { "dog" });
Object[] deserialized = deserializer.deserialize(stream, bark);
assertThat(deserialized.length, is(1));
assertThat(deserialized[0], is(instanceOf(Dog.class)));
Dog dog = (Dog) deserialized[0];
assertThat(dog.name, is("Brutus"));
assertThat(dog.age, is(7));
}
@Test
public void shouldBeAbleToDeserializeADogWithDeserializerAdapter() throws Exception {
List<JsonDeserializer> deserializers = new ArrayList<JsonDeserializer>();
deserializers.add(new DogDeserializer());
deserializer = new GsonDeserialization(provider, new DefaultJsonDeserializers(deserializers), request);
InputStream stream = new ByteArrayInputStream("{'dog':{'name':'Renan Reis','age':'0'}}".getBytes());
when(provider.parameterNamesFor(bark.getMethod())).thenReturn(new String[] { "dog" });
Object[] deserialized = deserializer.deserialize(stream, bark);
assertThat(deserialized.length, is(1));
assertThat(deserialized[0], is(instanceOf(Dog.class)));
Dog dog = (Dog) deserialized[0];
assertThat(dog.name, is("Renan"));
assertThat(dog.age, is(25));
}
@Test
public void shouldBeAbleToDeserializeADogWhenMethodHasMoreThanOneArgument() throws Exception {
InputStream stream = new ByteArrayInputStream("{'dog':{'name':'Brutus','age':7}}".getBytes());
when(provider.parameterNamesFor(jump.getMethod())).thenReturn(new String[] { "dog", "times" });
Object[] deserialized = deserializer.deserialize(stream, jump);
assertThat(deserialized.length, is(2));
assertThat(deserialized[0], is(instanceOf(Dog.class)));
Dog dog = (Dog) deserialized[0];
assertThat(dog.name, is("Brutus"));
assertThat(dog.age, is(7));
}
@Test
public void shouldBeAbleToDeserializeADogWhenMethodHasMoreThanOneArgumentAndHasNotRoot() throws Exception {
InputStream stream = new ByteArrayInputStream("{'name':'Brutus','age':7}".getBytes());
when(provider.parameterNamesFor(jump.getMethod())).thenReturn(new String[] { "dog", "times" });
Object[] deserialized = deserializer.deserialize(stream, jump);
assertThat(deserialized.length, is(2));
assertThat(deserialized[0], is(instanceOf(Dog.class)));
Dog dog = (Dog) deserialized[0];
assertThat(dog.name, is("Brutus"));
assertThat(dog.age, is(7));
}
@Test
public void shouldBeAbleToDeserializeADogWhenMethodHasMoreThanOneArgumentAndTheXmlIsTheLastOne() throws Exception {
InputStream stream = new ByteArrayInputStream("{'dog':{'name':'Brutus','age':7}}".getBytes());
when(provider.parameterNamesFor(dropDead.getMethod())).thenReturn(new String[] { "times", "dog" });
Object[] deserialized = deserializer.deserialize(stream, dropDead);
assertThat(deserialized.length, is(2));
assertThat(deserialized[1], is(instanceOf(Dog.class)));
Dog dog = (Dog) deserialized[1];
assertThat(dog.name, is("Brutus"));
assertThat(dog.age, is(7));
}
@Test
public void shouldBeAbleToDeserializeADogNamedDifferently() throws Exception {
InputStream stream = new ByteArrayInputStream("{'pet':{'name':'Brutus','age':7}}".getBytes());
when(provider.parameterNamesFor(bark.getMethod())).thenReturn(new String[] { "pet" });
Object[] deserialized = deserializer.deserialize(stream, bark);
assertThat(deserialized.length, is(1));
assertThat(deserialized[0], is(instanceOf(Dog.class)));
Dog dog = (Dog) deserialized[0];
assertThat(dog.name, is("Brutus"));
assertThat(dog.age, is(7));
}
@Test
public void shouldDeserializeADogWithCalendarAttribute() {
InputStream stream = new ByteArrayInputStream(
"{'dog':{'name':'Brutus','age':7,'birthday':'06/01/1987'}}".getBytes());
when(provider.parameterNamesFor(bark.getMethod())).thenReturn(new String[] { "dog" });
when(provider.parameterNamesFor(bark.getMethod())).thenReturn(new String[] { "dog" });
Object[] deserialized = deserializer.deserialize(stream, bark);
assertThat(deserialized.length, is(1));
assertThat(deserialized[0], is(instanceOf(Dog.class)));
Dog dog = (Dog) deserialized[0];
assertThat(dog.name, is("Brutus"));
assertThat(dog.age, is(7));
Calendar birthday = new GregorianCalendar(1987, 0, 6);
assertThat(dog.birthday, is(birthday));
}
@Test
public void shouldDeserializeADogWithCalendarAsISO8601Attribute() {
InputStream stream = new ByteArrayInputStream(
"{'dog':{'name':'Brutus','age':7,'birthday':'2013-07-23T17:14:14.000-0300'}}".getBytes());
when(provider.parameterNamesFor(bark.getMethod())).thenReturn(new String[] { "dog" });
List<JsonDeserializer> deserializers = new ArrayList<JsonDeserializer>();
deserializers.add(new br.com.caelum.vraptor.serialization.iso8601.gson.CalendarISO8601Deserializer(new ISO8601Util()));
deserializer = new GsonDeserialization(provider, new DefaultJsonDeserializers(deserializers), request);
Object[] deserialized = deserializer.deserialize(stream, bark);
assertThat(deserialized.length, is(1));
assertThat(deserialized[0], is(instanceOf(Dog.class)));
Dog dog = (Dog) deserialized[0];
assertThat(dog.name, is("Brutus"));
assertThat(dog.age, is(7));
Calendar birthday = new GregorianCalendar(2013, 6, 23, 17, 14, 14);
birthday.setTimeZone(TimeZone.getTimeZone("GMT-0300"));
assertThat(dog.birthday, is(birthday));
}
@Test
public void shouldDeserializeADogWithCalendarAsObjectAttribute() {
InputStream stream = new ByteArrayInputStream(
"{'dog':{'name':'Brutus','age':7,'birthday':{'time':1301886000000,'timezone':'America/Sao_Paulo'}}}".getBytes());
when(provider.parameterNamesFor(bark.getMethod())).thenReturn(new String[] { "dog" });
Object[] deserialized = deserializer.deserialize(stream, bark);
assertThat(deserialized.length, is(1));
assertThat(deserialized[0], is(instanceOf(Dog.class)));
Dog dog = (Dog) deserialized[0];
assertThat(dog.name, is("Brutus"));
assertThat(dog.age, is(7));
Calendar birthday = new GregorianCalendar(2011, 03, 04);//04/04/2011
birthday.setTimeZone(TimeZone.getTimeZone("America/Sao_Paulo"));
assertThat(dog.birthday, is(birthday));
}
@Test
public void shouldHonorRequestHeaderAcceptCharset() throws Exception {
InputStream stream = new ByteArrayInputStream("{'pet':{'name':'ç'}}".getBytes("ISO-8859-1"));
when(provider.parameterNamesFor(bark.getMethod())).thenReturn(new String[] { "pet" });
when(request.getHeader("Accept-Charset")).thenReturn("UTF-8,*;q=0.5");
Object[] deserialized = deserializer.deserialize(stream, bark);
assertThat(deserialized.length, is(1));
assertThat(deserialized[0], is(instanceOf(Dog.class)));
Dog dog = (Dog) deserialized[0];
assertThat(dog.name, is("ç"));
}
@Test
public void whenNoCharsetHeaderIsFoundThanAssumeItIsUTF8() throws Exception {
InputStream stream = new ByteArrayInputStream("{'pet':{'name':'ç'}}".getBytes("ISO-8859-1"));
when(provider.parameterNamesFor(bark.getMethod())).thenReturn(new String[] { "pet" });
when(request.getHeader("Accept-Charset")).thenReturn(null);
Object[] deserialized = deserializer.deserialize(stream, bark);
assertThat(deserialized.length, is(1));
assertThat(deserialized[0], is(instanceOf(Dog.class)));
Dog dog = (Dog) deserialized[0];
assertThat(dog.name, is("ç"));
}
@Test
public void shouldByPassDeserializationWhenHasNoContent() {
InputStream stream = new ByteArrayInputStream("".getBytes());
when(provider.parameterNamesFor(bark.getMethod())).thenReturn(new String[] { "pet" });
Object[] deserialized = deserializer.deserialize(stream, bark);
assertThat(deserialized.length, is(1));
assertThat(deserialized[0], is(nullValue()));
}
@Test
public void shouldDeserializeFromGenericTypeOneParam() {
InputStream stream = new ByteArrayInputStream(
"{'entity':{'name':'Brutus','age':7,'birthday':'06/01/1987'}}".getBytes());
ResourceClass resourceClass = new DefaultResourceClass(ExtGenericController.class);
Method method = new Mirror().on(GenericController.class).reflect().method("method").withAnyArgs();
ResourceMethod resource = new DefaultResourceMethod(resourceClass, method);
when(provider.parameterNamesFor(resource.getMethod())).thenReturn(new String[] { "entity" });
Object[] deserialized = deserializer.deserialize(stream, resource);
Dog dog = (Dog) deserialized[0];
assertThat(dog.name, equalTo("Brutus"));
}
@Test
public void shouldDeserializeFromGenericTypeTwoParams() {
InputStream stream = new ByteArrayInputStream(
"{'entity':{'name':'Brutus','age':7,'birthday':'06/01/1987'}, 'param': 'test'}".getBytes());
ResourceClass resourceClass = new DefaultResourceClass(ExtGenericController.class);
Method method = new Mirror().on(GenericController.class).reflect().method("anotherMethod").withAnyArgs();
ResourceMethod resource = new DefaultResourceMethod(resourceClass, method);
when(provider.parameterNamesFor(resource.getMethod())).thenReturn(new String[] { "entity", "param" });
Object[] deserialized = deserializer.deserialize(stream, resource);
Dog dog = (Dog) deserialized[0];
String param = (String) deserialized[1];
assertThat(dog.name, equalTo("Brutus"));
assertThat(param, equalTo("test"));
assertThat(deserialized.length, equalTo(2));
}
@Test
public void shouldDeserializeWithoutGenericType() {
InputStream stream = new ByteArrayInputStream(
"{'param': 'test'}".getBytes());
ResourceClass resourceClass = new DefaultResourceClass(ExtGenericController.class);
Method method = new Mirror().on(GenericController.class).reflect().method("methodWithoutGenericType").withArgs(String.class);
ResourceMethod resource = new DefaultResourceMethod(resourceClass, method);
when(provider.parameterNamesFor(resource.getMethod())).thenReturn(new String[] { "param" });
Object[] deserialized = deserializer.deserialize(stream, resource);
String param = (String) deserialized[0];
assertThat(param, equalTo("test"));
}
}