Efi MK
Efi MK

Reputation: 1042

Convert POJO to json in a conroller

I've managed to convert POGO to json via

class Test {
        String test
}
def local = new Test()
local.test = "1234"
render test as JSON

However when trying to convert a java class (declared in a different library) I'm always getting back the class type

public class RegistrationDetails {
    /**
     * The registration token used to identify the device from now on.
     */
    public String registrationToken;
}

RegistrationDetails details = new RegistrationDetails()
details.registrationToken="123"
render details as JSON

instead of getting

{
 "registrationToken":"123"
}

Instead I'm getting back

{
    "class": "data.com.shared.RegistrationDetails"
}

Am I missing something ?

Upvotes: 1

Views: 732

Answers (1)

Burt Beckwith
Burt Beckwith

Reputation: 75671

Converting an object to JSON is based on properties. String test in a Groovy class defines a property named "test" because it's a field with no scope modifier. It defaults to public, and the Groovy compiler converts String test to a private field and a getter and a setter. If you decompile Test (e.g. with jd-gui or another decompiler) you'll see something similar to this (with a bunch of other code that's not relevant here):

public class Test implements GroovyObject {

   private String test;

   ...

   public String getTest() {
      return test;
   }

   public void setTest(String paramString) {
      test = paramString;
   }
}

It won't replace an existing getter or setter, so you're free to customize either or both if you need custom logic when getting and/or setting. If you explicitly make the field public (public String test) or use any other scope modifier then this conversion doesn't occur.

This is how domain classes work; Hibernate doesn't have any support for Groovy but it doesn't need any - it sees the getters and setters like it would if you had created a typical verbose POJO. It's also how Spring bean dependency injection works; if you have a field in a controller/service/taglib/etc. like def sessionFactory or SessionFactory sessionFactory, Groovy adds a getter and setter, and Spring sees the setter and since Grails uses autowiring by name, if there's a bean named "sessionFactory" Spring will call your setter and inject it.

Your Java class doesn't have a property - it has a public field, and the Java compiler doesn't do anything special with it, and neither Groovy nor Grails do anything with it either since it's a Java class. So the only data that's available from the class via a getter is the class since every class has a getClass method.

The JSON conversion excludes the class "property" in Groovy classes but not Java but that appears to be a bug; the loop in GenericJavaBeanMarshaller (the helper class for POJOs) only excludes PropertyDescriptors that have no getter, but the loop in GroovyBeanMarshaller excludes the getMetaClass and getClass getters.

Upvotes: 3

Related Questions