Reputation: 9621
I have this method:
/**
* POST
*/
public static void create(String body) {
Logger.info("APPOINTMENT create - json string: %s", body);
Appointment appointment = null;
try {
appointment = new Gson().fromJson(body, Appointment.class);
//services are detached, re-take them from db
List<Service> refreshedServices = new ArrayList<Service>();
for (final Service ser : appointment.services) {
Service service = Service.findById(ser.id);
refreshedServices.add(service);
}
appointment.services = refreshedServices;
appointment.save();
appointment.refresh();
Logger.info("services refreshed");
} catch (Exception ex) {
Logger
.info(
"An error has occured when trying to create an APPOINTMENT %s",
ex);
response.status = Http.StatusCode.INTERNAL_ERROR;
renderJSON(new StatusMessage(
"An internal error has occured. Please try again later."));
}
renderJSON(appointment);
}
I'm testing it like this:
public void createAppointment(final Contact contact, final List<Service> services) throws Exception {
Appointment app = new Appointment();
app.userUid = "cristi-uid";
app.name = "app1";
app.contact = contact;
String serviceAsJson = "{\"userUid\":\"cristi-uid\",\"name\":\"app1\",\"allDay\":false,\"contact\":{\"id\":"+contact.id+"},\"services\":[{\"id\":\""+services.get(0).getId()+"\"},{\"id\":\""+services.get(1).getId()+"\"}]}";
Response response = POST("/appointment/create", "application/json", serviceAsJson);
Logger.info("POST was done");
Appointment appReturned = new Gson().fromJson(response.out.toString(), Appointment.class);
Logger.info("appointment create response: %s", response.out.toString());
assertIsOk(response);
assertEquals(appReturned.name, app.name);
}
Well, the issue is that it is throwing this exception:
java.lang.RuntimeException: java.util.concurrent.ExecutionException: play.exceptions.JavaExecutionException
at play.test.FunctionalTest.makeRequest(FunctionalTest.java:304)
at play.test.FunctionalTest.makeRequest(FunctionalTest.java:310)
at play.test.FunctionalTest.POST(FunctionalTest.java:152)
at play.test.FunctionalTest.POST(FunctionalTest.java:120)
at play.test.FunctionalTest.POST(FunctionalTest.java:116)
at AppointmentsTest.createAppointment(AppointmentsTest.java:61)
and I am unable to find out why.
It prints out Logger.info("services refreshed");
after that it is throwing the exception...
Do you guys see anything wrong with this test POST?
UPDATE: Seems that the issues comes from trying to render the appointment
as JSON:
Caused by: java.lang.StackOverflowError
at java.util.LinkedHashMap$LinkedHashIterator.(LinkedHashMap.java:345)
at java.util.LinkedHashMap$LinkedHashIterator.(LinkedHashMap.java:345)
at java.util.LinkedHashMap$ValueIterator.(LinkedHashMap.java:387)
at java.util.LinkedHashMap$ValueIterator.(LinkedHashMap.java:387)
at java.util.LinkedHashMap.newValueIterator(LinkedHashMap.java:397)
at java.util.HashMap$Values.iterator(HashMap.java:910)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:192)
at com.google.gson.Gson$FutureTypeAdapter.write(Gson.java:879)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:96)
Upvotes: 3
Views: 992
Reputation: 1296
It is because:
The Play framework comes bundled with Google’s JSON library Gson, but the developers of this library have made some design choices that keep it from being ideal for generating JSON that is going to be sent to the HTTP client.
Erik Bakker recommended to use FlexSon
Upvotes: 1
Reputation: 9621
I was able to identify the issues by going down and studying the error trace. Basically my Appointment
object has some ManyToMany
relations and it seems that renderJSON was giving StackOverFlow
when trying to render those relations.
I've created another Appointment
object and copy into it only the fields I need to be exported.
Appointment appointmentOutput = new Appointment();
appointmentOutput.id = appointment.id;
appointmentOutput.name = appointment.name;
renderJSON(appointmentOutput);
Upvotes: 0